package logic.nodes;

import logic.ships.moveableShip.MovableShip;

import com.jme.input.controls.GameControl;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Spatial;

public class MoveForwardController extends Controller implements MovingController {
	
	private static final long serialVersionUID = 1L;

	protected Spatial node;
	protected GameControl forwardControl, breakControl;
	protected float normalMaxSpeed, boostMaxSpeed, currentMaxSpeed, currentSpeed;
	protected float normalAcceleration, currentAcceleration, boostAcceleration, breaking;
	protected boolean isStopping, wasBoosting;
	
	protected Vector3f currentDir;
		
	public MoveForwardController(Spatial node, GameControl forwardControl, float maxSpeed, 
			float boostSpeed, float acceleration, GameControl breakControl, float breaking) {
		this.node = node;
		this.forwardControl = forwardControl;
		normalMaxSpeed = maxSpeed;
		currentMaxSpeed = normalMaxSpeed;
		boostMaxSpeed = boostSpeed;
		normalAcceleration = acceleration;
		boostAcceleration = normalAcceleration * 2f;
		currentAcceleration = normalAcceleration;
		this.breakControl = breakControl;
		this.breaking = breaking;
		currentDir = Vector3f.ZERO.clone();
	}
	
	public void enableBoost(boolean enable) {
		if(enable) {
			currentMaxSpeed = boostMaxSpeed;
			currentAcceleration = boostAcceleration;
		} else {
			currentMaxSpeed = normalMaxSpeed;
			currentAcceleration = normalAcceleration;
		}
		wasBoosting = !enable;
	}
	
	public boolean isBoosting() { return currentMaxSpeed == boostMaxSpeed; }
	
	public float getThrust() { return forwardControl.getValue() - breakControl.getValue(); }
	
	@Override
	public float getCurrentSpeed() { return FastMath.abs(currentSpeed); }
	
	@Override
	public Vector3f getMoveDirection() { return currentDir.normalize(); }
	
	public void setCurrentSpeed(float newSpeed) {
		currentSpeed = newSpeed;
		if(node instanceof MovableShip) {
			MovableShip ship = (MovableShip)node;
			if(ship.getMoveForwardController() == this) ship.changeSpeed(getCurrentSpeed());
		}
	}
	
	public float getBoostSpeed() { return boostMaxSpeed; }
	
	@Override
	public void stop(boolean stop) { isStopping = stop; }
	
	public boolean isStopping() { return isStopping; }
	
	public void setMaxSpeed(float maxSpeed) { currentMaxSpeed = maxSpeed; }
	
	public void setNormalMaxSpeed(float normalMaxSpeed) { this.normalMaxSpeed = normalMaxSpeed; }
	
	public void setBoostMaxSpeed(float boostMaxSpeed) { this.boostMaxSpeed = boostMaxSpeed; }
	
	public void setNormalAcceleration(float normalAcceleration) {
		this.normalAcceleration = normalAcceleration;
		boostAcceleration = normalAcceleration * 2f;
	}
	
	public void setBreaking(float breaking) { this.breaking = breaking; }
	
	@Override
	public void update(float time) {				
		float value = getThrust();
		if(isStopping) {
			if(currentSpeed > 0f) value = -1f;
			else value = 0f;
		}
		if(wasBoosting) {
			if(currentSpeed > currentMaxSpeed) value = -1f + (value < 0 ? value : -value);
			else wasBoosting = false;
		}
		float delta = currentAcceleration * time;
		float max = currentMaxSpeed;
		
		if(value > 0f) max = currentMaxSpeed * value;
		else if(currentSpeed == 0f) max = 0f;
		
		if(value < 0f) delta = -breaking * time * 1.5f;
		else if(value == 0f) 
			delta = time * (currentSpeed < 0f ? breaking : -breaking);
		
		if(((currentSpeed > 0f) && currentSpeed + delta < 0f) 
		|| (currentSpeed < 0f && currentSpeed + delta > 0f)) 
			currentSpeed = 0f;
		else currentSpeed += delta;
		
		if(currentSpeed > max && !wasBoosting) currentSpeed = max;
		if(currentSpeed != 0f) move(time * 60);
		setCurrentSpeed(currentSpeed);
	}
	
	protected void move(float tpf) {
		currentDir = node.getLocalTranslation().clone();
		Vector3f forwardStep = node.getLocalRotation().getRotationColumn(2).mult(currentSpeed * tpf);
		node.getLocalTranslation().addLocal(forwardStep);
		currentDir = node.getLocalTranslation().subtract(currentDir);
	}
}